package ufr_stgi.assistance_conduite.bdd;

import java.util.*;

import ufr_stgi.assistance_conduite.MonApplication;
import ufr_stgi.assistance_conduite.modele.Panneau;
import ufr_stgi.assistance_conduite.modele.TypePanneau;

import android.content.*;
import android.database.Cursor;
import android.database.sqlite.*;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.util.Log;

/**
 * Gestion de la base de données SQLite sur le téléphone avec toutes les opérations possibles (ajout de panneaux, modification, ...)
 * @author Guillaume MONTAVON & Renaud DAVID (Master 2 RIM)
 */
public class MaBaseSQLite extends SQLiteOpenHelper {
	
	protected SQLiteDatabase db = null; //lien vers la BdD
	
	public static String TABLE_PANNEAU = "panneau";
	public static String TABLE_PANNEAU_TEMP = "panneautemp";
	public static String TABLE_TYPE_PANNEAU = "typepanneau";
	public static String TABLE_IMAGE_MANQUANTE = "imagemanquante";
	
	private static String CREATE_TABLE_PANNEAU = "create table " + TABLE_PANNEAU + " ("
		+ "idPanneau INTEGER PRIMARY KEY,"
		+ "latitudePanneau DOUBLE not null,"
		+ "longitudePanneau DOUBLE not null,"
		+ "nbMarquage INTEGER,"
		+ "cheminPhoto varchar(255),"
		+ "fiabilitePanneau FLOAT,"
		+ "direction INTEGER,"
		+ "idType INTEGER not null,"
		+ "foreign key(idType) references " + TABLE_TYPE_PANNEAU + "(idType))";
	
	private static String CREATE_TABLE_PANNEAU_TEMP = "create table " + TABLE_PANNEAU_TEMP + " ("
		+ "idPanneau INTEGER PRIMARY KEY AUTOINCREMENT,"
		+ "latitudePanneau DOUBLE not null,"
		+ "longitudePanneau DOUBLE not null,"
		+ "cheminPhoto varchar(255),"
		+ "direction INTEGER"
		+ ")";
	
	private static String CREATE_TABLE_TYPE_PANNEAU = "create table " + TABLE_TYPE_PANNEAU + " ("
		+ "idType INTEGER PRIMARY KEY,"
		+ "libelleType varchar(64) not null,"
		+ "cheminPhotoExemple varchar(255)"
		+ ")";
	
	private static String CREATE_TABLE_IMAGE_MANQUANTE = "create table " + TABLE_IMAGE_MANQUANTE + " ("
		+ "idPanneau INTEGER PRIMARY KEY,"
		+ "foreign key(idPanneau) references " + TABLE_PANNEAU + "(idPanneau))";
	
	
	public MaBaseSQLite(Context context, String name, CursorFactory factory, int version) {
		super(context, name, factory, version);
	}
	
	/* (non-Javadoc)
	 * @see android.database.sqlite.SQLiteOpenHelper#onCreate(android.database.sqlite.SQLiteDatabase)
	 */
	@Override
	public void onCreate(SQLiteDatabase db) {
		//open();
		db.execSQL(CREATE_TABLE_PANNEAU);
		db.execSQL(CREATE_TABLE_PANNEAU_TEMP);
		db.execSQL(CREATE_TABLE_TYPE_PANNEAU);
		db.execSQL(CREATE_TABLE_IMAGE_MANQUANTE);
		//close();
	}
	
	/* (non-Javadoc)
	 * @see android.database.sqlite.SQLiteOpenHelper#onUpgrade(android.database.sqlite.SQLiteDatabase, int, int)
	 */
	@Override
	public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
		//open();
		db.execSQL("drop table if exists " + TABLE_IMAGE_MANQUANTE);
		db.execSQL("drop table if exists " + TABLE_PANNEAU_TEMP);
		db.execSQL("drop table if exists " + TABLE_PANNEAU);
		db.execSQL("drop table if exists " + TABLE_TYPE_PANNEAU);
		onCreate(db);
		//close();
	}
	
	public MaBaseSQLite open(){
		db = getWritableDatabase();
		return this;
	}
	
	public void close(){
		db.close();
	}
	
	public SQLiteDatabase getDb() {
		return db;
	}
	
	/**
	 * Ajoute une image manquante dans la BdD
	 * @param idPanneau panneau dont il manque son image
	 * @param plusieurs true si on a déjà une connexion à la BdD ouverte sinon false
	 * @return true si pas d'erreur, false sinon
	 */
	public synchronized boolean ajouterImageManquante(long idPanneau, boolean plusieurs) {
		
		if(!plusieurs)
			open();
		
		ContentValues imageManquanteToInsert = new ContentValues();
		imageManquanteToInsert.put("idPanneau", idPanneau);
		
		long nouveauId = db.replace(TABLE_IMAGE_MANQUANTE, null, imageManquanteToInsert);
		
		if(!plusieurs)
			close();
		
		if(nouveauId != -1)
			return true;
		else
			return false;
	
	}
	
	/**
	 * Permet d'ajouter la liste des panneaux qui n'ont pas d'image dans la BdD
	 * @param listePanneau liste des panneaux qui n'ont pas d'image
	 * @return true si l'opération a réussi
	 */
	public synchronized boolean ajouterListeImageManquante(ArrayList<Panneau> listePanneau) {
		
		open();
		
		boolean reussi = true;
		
		for(Panneau p : listePanneau)
			if(!ajouterImageManquante(p.getIdentifiant(), true))
				reussi = false;
		
		close();
		
		return reussi;
		
	}
	
	/**
	 * Permet d'obtenir la liste de toutes les images manquantes de la base de données
	 * @return liste des images manquantes
	 */
	public synchronized ArrayList<Long> getListeImageManquante() {
		
		open();
		
		ArrayList<Long> listeImageManquante = new ArrayList<Long>();
		
		String[] colonnesARecup = new String[] { "idPanneau" };
		
		Cursor cursorResults = db.query(TABLE_IMAGE_MANQUANTE, colonnesARecup, null, null, null, null, "idPanneau asc", null);
		int columnId = cursorResults.getColumnIndex("idPanneau");
		
		if (null != cursorResults) {
			if (cursorResults.moveToFirst()) {
				do {
					listeImageManquante.add(cursorResults.getLong(columnId));
				} while (cursorResults.moveToNext());
			}
		}
		
		cursorResults.close();
		
		close();
		
		return listeImageManquante;
		
	}
	
	/**
	 * Supprime une image manquante dans la BdD
	 * @param idPanneau identifiant du panneau à supprimer
	 * @return true si l'opération a réussi
	 */
	public synchronized boolean supprimerImageManquante(long idPanneau) {
		
		boolean reussi=true;
		open();
		
		if(db.delete(TABLE_IMAGE_MANQUANTE, "idPanneau=" + idPanneau, null)<1)
			reussi = false;
		
		close();
		return reussi;
		
	}
	
	/**
	 * Permet d'obtenir un panneau en donnant son identifiant
	 * @param idPanneau identifiant du panneau demandé
	 * @return panneau demandé
	 */
	public synchronized Panneau getPanneau(long idPanneau) {
		
		open();
		
		Panneau retour = null;
		
		String[] colonnesARecup = new String[] { "latitudePanneau", "longitudePanneau", "nbMarquage", "cheminPhoto", "fiabilitePanneau", "direction", "idType" };
		
		Cursor cursorResults = db.query(TABLE_PANNEAU, colonnesARecup, "idPanneau=" + idPanneau, null, null, null, "idPanneau asc", null);
		int columnLat = cursorResults.getColumnIndex("latitudePanneau");
		int columnLon = cursorResults.getColumnIndex("longitudePanneau");
		int columnNbMarquage = cursorResults.getColumnIndex("nbMarquage");
		int columnChemin = cursorResults.getColumnIndex("cheminPhoto");
		int columnFiabilite = cursorResults.getColumnIndex("fiabilitePanneau");
		int columnDirection = cursorResults.getColumnIndex("direction");
		int columnType = cursorResults.getColumnIndex("idType");
		
		
		if (null != cursorResults) {
			if (cursorResults.moveToFirst())
				retour = new Panneau(idPanneau, cursorResults.getDouble(columnLat), cursorResults.getDouble(columnLon), cursorResults.getInt(columnNbMarquage), cursorResults.getString(columnChemin), cursorResults.getFloat(columnFiabilite), cursorResults.getInt(columnDirection), cursorResults.getLong(columnType));
		}
		
		cursorResults.close();
		
		close();
		
		return retour;
		
	}
	
	/**
	 * Permet d'obtenir la liste de tous les panneaux de la base de données
	 * @return liste des panneaux
	 */
	public synchronized ArrayList<Panneau> getListePanneau(boolean tous, double latitude, double longitude) {
		
		open();
		
		String where = null;
		if(!tous)
			where = "CAST((latitudePanneau/" + MonApplication.TAILLE_ZONE_POSITION + ") AS INTEGER) = " + (int)(latitude / MonApplication.TAILLE_ZONE_POSITION) + " AND CAST((longitudePanneau/" + MonApplication.TAILLE_ZONE_POSITION + ") AS INTEGER) = " + (int)(longitude / MonApplication.TAILLE_ZONE_POSITION);
				
		ArrayList<Panneau> listePanneau = new ArrayList<Panneau>();
		
		String[] colonnesARecup = new String[] { "idPanneau", "latitudePanneau", "longitudePanneau", "nbMarquage", "cheminPhoto", "fiabilitePanneau", "direction", "idType" };
		
		Cursor cursorResults = db.query(TABLE_PANNEAU, colonnesARecup, where, null, null, null, "idPanneau asc", null);
		int columnId = cursorResults.getColumnIndex("idPanneau");
		int columnLat = cursorResults.getColumnIndex("latitudePanneau");
		int columnLon = cursorResults.getColumnIndex("longitudePanneau");
		int columnNbMarquage = cursorResults.getColumnIndex("nbMarquage");
		int columnChemin = cursorResults.getColumnIndex("cheminPhoto");
		int columnFiabilite = cursorResults.getColumnIndex("fiabilitePanneau");
		int columnDirection = cursorResults.getColumnIndex("direction");
		int columnType = cursorResults.getColumnIndex("idType");
		
		if (null != cursorResults) {
			if (cursorResults.moveToFirst()) {
				do {
					listePanneau.add(new Panneau(cursorResults.getLong(columnId), cursorResults.getDouble(columnLat), cursorResults.getDouble(columnLon), cursorResults.getInt(columnNbMarquage), cursorResults.getString(columnChemin), cursorResults.getFloat(columnFiabilite), cursorResults.getInt(columnDirection), cursorResults.getLong(columnType)));
				} while (cursorResults.moveToNext());
			}
		}
		
		cursorResults.close();
		
		close();
		
		return listePanneau;
		
	}
	
	/**
	 * Permet d'obtenir la liste de tous les panneaux temporaires de la base de données
	 * @return liste des panneaux
	 */
	public synchronized ArrayList<Panneau> getListePanneauTemp() {
		
		open();
		
		ArrayList<Panneau> listePanneau = new ArrayList<Panneau>();
		
		String[] colonnesARecup = new String[] { "idPanneau", "latitudePanneau", "longitudePanneau", "cheminPhoto", "direction" };
		
		Cursor cursorResults = db.query(TABLE_PANNEAU_TEMP, colonnesARecup, null, null, null, null, "idPanneau asc", null);
		int columnId = cursorResults.getColumnIndex("idPanneau");
		int columnLat = cursorResults.getColumnIndex("latitudePanneau");
		int columnLon = cursorResults.getColumnIndex("longitudePanneau");
		int columnChemin = cursorResults.getColumnIndex("cheminPhoto");
		int columnDirection = cursorResults.getColumnIndex("direction");
		
		if (null != cursorResults) {
			if (cursorResults.moveToFirst()) {
				do {
					listePanneau.add(new Panneau(cursorResults.getLong(columnId), cursorResults.getDouble(columnLat), cursorResults.getDouble(columnLon), 0, cursorResults.getString(columnChemin), 0, cursorResults.getInt(columnDirection), 0));
				} while (cursorResults.moveToNext());
			}
		}
		
		cursorResults.close();
		
		close();
		
		return listePanneau;
		
	}
	
	/**
	 * Ajoute un panneau temporaire qui sera envoyé au serveur dans la BdD
	 * @param panneau panneau à ajouter
	 * @param plusieurs true si on a déjà une connexion à la BdD ouverte sinon false
	 * @return identifiant du panneau ajouté, -1 si erreur
	 */
	public synchronized long ajouterPanneauTemp(Panneau panneau, boolean plusieurs) {
		
		if(!plusieurs)
			open();
		
		ContentValues panneauToInsert = new ContentValues();
		panneauToInsert.put("latitudePanneau", panneau.getLatitude());
		panneauToInsert.put("longitudePanneau", panneau.getLongitude());
		panneauToInsert.put("cheminPhoto", panneau.getChemin());
		panneauToInsert.put("direction", panneau.getDirection());
		
		long nouveauId = (int) db.insert(TABLE_PANNEAU_TEMP, null, panneauToInsert);
		
		if(!plusieurs)
			close();
		
		return nouveauId;
	
	}
	
	/**
	 * Ajoute un panneau dans la BdD
	 * @param panneau panneau à ajouter
	 * @param plusieurs true si on a déjà une connexion à la BdD ouverte sinon false
	 * @return identifiant du panneau ajouté, -1 si erreur
	 */
	public synchronized long ajouterPanneau(Panneau panneau, boolean plusieurs) {
		
		if(!plusieurs)
			open();
		
		long nouveauId = panneau.getIdentifiant();
		
		Cursor cursorResults = db.query(TABLE_PANNEAU, null, "idPanneau=" + panneau.getIdentifiant(), null, null, null, "idPanneau asc", null);
		if(cursorResults.getCount() > 0) {
			cursorResults.close();
			Log.i("existe", panneau.getIdentifiant() + " existe deja");
		}
		else {
			Log.i("n'existe pas", panneau.getIdentifiant() + " n'existe pas");
			
			ContentValues panneauToInsert = new ContentValues();
			if(panneau.getIdentifiant() > 0)
				panneauToInsert.put("idPanneau", panneau.getIdentifiant());
			panneauToInsert.put("latitudePanneau", panneau.getLatitude());
			panneauToInsert.put("longitudePanneau", panneau.getLongitude());
			panneauToInsert.put("nbMarquage", panneau.getNbMarquage());
			panneauToInsert.put("cheminPhoto", panneau.getChemin());
			panneauToInsert.put("fiabilitePanneau", panneau.getFiabilite());
			panneauToInsert.put("direction", panneau.getDirection());
			panneauToInsert.put("idType", panneau.getIdType());
					
			nouveauId = (int) db.replace(TABLE_PANNEAU, null, panneauToInsert);
			
			ajouterImageManquante(nouveauId, true);
		}
		
		if(!plusieurs)
			close();

		return nouveauId;
	
	}
	
	
	/**
	 * Supprime un panneau dans la BdD
	 * @param idPanneau identifiant du panneau à supprimer
	 * @return true si l'opération a réussi
	 */
	public synchronized boolean supprimerPanneau(long idPanneau) {
		
		boolean reussi=true;
		open();
		
		if(db.delete(TABLE_PANNEAU, "idPanneau=" + idPanneau, null)<1)
			reussi = false;
		
		close();
		return reussi;
		
	}
	
	/**
	 * Supprime un panneau temporaire dans la BdD
	 * @param idPanneau identifiant du panneau à supprimer
	 * @return true si l'opération a réussi
	 */
	public synchronized boolean supprimerPanneauTemp(long idPanneau) {
		
		boolean reussi=true;
		open();
		
		if(db.delete(TABLE_PANNEAU_TEMP, "idPanneau=" + idPanneau, null)<1)
			reussi = false;
		
		close();
		return reussi;
		
	}
	
	/**
	 * Permet d'obtenir un type de panneau en donnant son identifiant
	 * @param idType identifiant du type de panneau demandé
	 * @return type demandé
	 */
	public synchronized TypePanneau getType(long idType) {
		
		open();
		
		TypePanneau retour = null;
		
		String[] colonnesARecup = new String[] { "libelleType", "cheminPhotoExemple" };
		
		Cursor cursorResults = db.query(TABLE_TYPE_PANNEAU, colonnesARecup, "idType=" + idType, null, null, null, "idType asc", null);
		int columnLibelle = cursorResults.getColumnIndex("libelleType");
		int columnChemin = cursorResults.getColumnIndex("cheminPhotoExemple");
		
		
		if (null != cursorResults) {
			if (cursorResults.moveToFirst())
				retour = new TypePanneau(idType, cursorResults.getString(columnLibelle), cursorResults.getString(columnChemin));
		}
		
		cursorResults.close();
		
		close();
		
		return retour;
		
	}
	
	/**
	 * Permet d'obtenir la liste de tous les types de panneau
	 * @return liste de tous les types de panneau
	 */
	public synchronized ArrayList<TypePanneau> getListeType() {
		
		open();
		
		ArrayList<TypePanneau> listeType = new ArrayList<TypePanneau>();
		
		String[] colonnesARecup = new String[] { "idType", "libelleType", "cheminPhotoExemple" };
		
		Cursor cursorResults = db.query(TABLE_TYPE_PANNEAU, colonnesARecup, null, null, null, null, "idType asc", null);
		int columnId = cursorResults.getColumnIndex("idType");
		int columnLibelle = cursorResults.getColumnIndex("libelleType");
		int columnChemin = cursorResults.getColumnIndex("cheminPhotoExemple");
		
		
		if (null != cursorResults) {
			if (cursorResults.moveToFirst()) {
				do {
					listeType.add(new TypePanneau(cursorResults.getLong(columnId), cursorResults.getString(columnLibelle), cursorResults.getString(columnChemin)));
				} while (cursorResults.moveToNext());
			}
		}
		
		cursorResults.close();
		
		close();
		
		return listeType;
		
	}
	
	/**
	 * Ajoute un tag dans la BdD
	 * @param tag tag à ajouter
	 * @param plusieurs true si on a déjà une connexion à la BdD ouverte sinon false
	 * @return identifiant du tag ajouté, -1 si erreur
	 */
	public synchronized long ajouterType(TypePanneau typePanneau, boolean plusieurs) {
		
		if(!plusieurs)
			open();
		
		ContentValues typeToInsert = new ContentValues();
		
		typeToInsert.put("idType", typePanneau.getIdentifiant());
		typeToInsert.put("libelleType", typePanneau.getLibelle());
		typeToInsert.put("cheminPhotoExemple", typePanneau.getChemin());
		
		long nouveauId = db.replace(TABLE_TYPE_PANNEAU, null, typeToInsert);
		typePanneau.setIdentifiant(nouveauId);
		
		if(!plusieurs)
			close();
		
		return nouveauId;
	
	}
	
	/**
	 * Permet d'ajouter une liste de panneaux dans la BdD
	 * @param listePanneau liste des panneaux à ajouter
	 * @return true si l'opération a réussi
	 */
	public synchronized boolean ajouterListePanneaux(ArrayList<Panneau> listePanneau) {
		
		open();
		
		boolean reussi = true;
		
		for(Panneau p : listePanneau)
			if(ajouterPanneau(p, true) < 1)
				reussi = false;
		
		close();
		
		return reussi;
		
	}
	
	/**
	 * Permet d'ajouter une liste de types de panneau dans la BdD
	 * @param listeType liste des types de panneau à ajouter
	 * @return true si l'opération a réussi
	 */
	public synchronized boolean ajouterListeType(ArrayList<TypePanneau> listeType) {
		
		open();
		
		boolean reussi = true;
		
		for(TypePanneau t : listeType)
			if(ajouterType(t, true) < 1)
				reussi = false;
		
		close();
		
		return reussi;
		
	}
	
	/**
	 * Vide toutes les tables de la BdD
	 */
	public void viderToutesTables() {
		onUpgrade(db, 1, 1);
	}
	
}
